/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.system.service.impl;

import cn.hutool.core.lang.UUID;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import lombok.RequiredArgsConstructor;
import me.zhengjie.config.FileProperties;
import me.zhengjie.config.enums.QrCodeTypeEnum;
import me.zhengjie.config.utils.QrCodeUtils;
import me.zhengjie.constant.ConstantUtils;
import me.zhengjie.enums.RedisKeyEnum;
import me.zhengjie.exception.EntityExistException;
import me.zhengjie.modules.system.domain.*;
import me.zhengjie.modules.system.repository.CourseInfoRepository;
import me.zhengjie.modules.system.repository.CourseItemRepository;
import me.zhengjie.modules.system.service.CourseClassService;
import me.zhengjie.modules.system.service.CourseInfoClockSourceService;
import me.zhengjie.modules.system.service.CourseInfoService;
import me.zhengjie.modules.system.service.dto.CourseInfoDto;
import me.zhengjie.modules.system.service.dto.CourseInfoQueryCriteria;
import me.zhengjie.modules.system.service.mapstruct.CourseInfoClockSourcePlusMapper;
import me.zhengjie.modules.system.service.mapstruct.CourseInfoMapper;
import me.zhengjie.modules.system.service.mapstruct.CourseItemExpMapper;
import me.zhengjie.utils.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.MessageFormat;
import java.util.*;

/**
* @website https://el-admin.vip
* @description 服务实现
* @author 王宇
* @date 2023-09-26
**/
@Service
@RequiredArgsConstructor
public class CourseInfoServiceImpl implements CourseInfoService {

    private final CourseInfoRepository courseInfoRepository;
    private final CourseInfoMapper courseInfoMapper;

    private final CourseItemRepository courseItemRepository;

    @Autowired
    private CourseItemExpMapper courseItemExpMapper;

    @Autowired
    private CourseInfoClockSourceService courseInfoClockSourceService;

    @Autowired
    private CourseClassService courseClassService;

    @Autowired
    private CourseInfoClockSourcePlusMapper courseInfoClockSourcePlusMapper;

    @Autowired
    FileProperties properties;

    @Value("${qrcode.signInUrl}")
    String signInUrl;

    @Autowired
    private RedisUtils redisUtils;
    @Override
    public Map<String,Object> queryAll(CourseInfoQueryCriteria criteria, Pageable pageable){
        Page<CourseInfo> page = courseInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(courseInfoMapper::toDto));
    }

    @Override
    public List<CourseInfoDto> queryAll(CourseInfoQueryCriteria criteria){
        return courseInfoMapper.toDto(courseInfoRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public CourseInfoDto findById(Long courseId) {
        CourseInfo courseInfo = courseInfoRepository.findById(courseId).orElseGet(CourseInfo::new);
        ValidationUtil.isNull(courseInfo.getCourseId(),"CourseInfo","courseId",courseId);
        return courseInfoMapper.toDto(courseInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseInfoDto create(CourseInfo resources) {
        if(courseInfoRepository.findByCourseNo(resources.getCourseNo()) != null){
            throw new EntityExistException(CourseInfo.class,"course_no",resources.getCourseNo());
        }
        return courseInfoMapper.toDto(courseInfoRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CourseInfoDto add(CourseInfoRequest request) {
        CourseInfo resources = new CourseInfo();
        BeanUtils.copyProperties(request,resources);
        String courseNo = UUID.fastUUID().toString(true);
        resources.setCourseNo(courseNo);
        resources.setCreateby(SecurityUtils.getCurrentUsername());
        resources.setCreateTime(new Timestamp(System.currentTimeMillis()));
        resources.setApplicants(ConstantUtils.Applicants);

        String content = MessageFormat.format(signInUrl,courseNo);
        String codeUrl = QrCodeUtils.getInstance().generate(content, QrCodeTypeEnum.CourseSignIn);

        resources.setSigninPic(codeUrl.replace(properties.getPath().getNgx(),""));

        CourseInfo save = courseInfoRepository.save(resources);
        if (CollectionUtils.isEmpty(request.getItems())){
            return courseInfoMapper.toDto(save);
        }
        redisUtils.set(RedisKeyEnum.getCourseInfoKey(courseNo), save);
        List<CourseItem> itemList = new ArrayList<>();
        request.getItems().forEach(s -> {
            CourseItem courseItem = new CourseItem();
            courseItem.setCreateby(SecurityUtils.getCurrentUsername());
            courseItem.setCreateTime(DateUtil.TimestampNow());
            courseItem.setCourseNo(courseNo);
            courseItem.setItemKey(ConstantUtils.COURSE_CATEGORY_KEY);
            courseItem.setItemValue(s.getItemValue());
            courseItem.setItemTitle(s.getItemTitle());
            courseItem.setItemStatus(ElAdminConstant.Valid);
            courseItem.setTrysee(s.getTrysee());
            courseItem.setDuration(s.getDuration());
            itemList.add(courseItem);
        });
        courseItemRepository.saveAll(itemList);

        if (CollectionUtils.isNotEmpty(request.getClassNoList())){
            request.getClassNoList().forEach(s -> {
                CourseInfoClockSource courseInfoClockSource = new CourseInfoClockSource();
                courseInfoClockSource.setCourseNo(courseNo);
                courseInfoClockSource.setClassNo(s);
                courseInfoClockSource.setCreateby(SecurityUtils.getCurrentUsername());
                courseInfoClockSource.setCreateTime(DateUtil.TimestampNow());
                CourseClass courseClass = courseClassService.getClassByClassNo(s);
                if (Objects.nonNull(courseClass)){
                    courseInfoClockSource.setClassName(courseClass.getName());
                    courseInfoClockSource.setClassId(courseClass.getClassId());
                }
                courseInfoClockSourceService.create(courseInfoClockSource);
            });

        }
        return courseInfoMapper.toDto(save);
    }

    @Override
    public void modify(CourseInfoRequest resources) {
        CourseInfo courseInfo = courseInfoRepository.findById(resources.getCourseId()).orElseGet(CourseInfo::new);
        ValidationUtil.isNull( courseInfo.getCourseId(),"CourseInfo","id",resources.getCourseId());
        BeanUtils.copyProperties(resources,courseInfo);
        courseInfo.setUpdateby(SecurityUtils.getCurrentUsername());
        courseInfo.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        courseInfo.setApplicants(ConstantUtils.Applicants);
        if (StringUtils.isBlank(courseInfo.getSigninPic())){
            String content = MessageFormat.format(signInUrl,courseInfo.getCourseNo());
            String codeUrl = QrCodeUtils.getInstance().generate(content, QrCodeTypeEnum.CourseSignIn);
            courseInfo.setSigninPic(codeUrl.replace(properties.getPath().getNgx(),""));
        }
        courseInfoRepository.save(courseInfo);

        redisUtils.set(RedisKeyEnum.getCourseInfoKey(courseInfo.getCourseNo()), courseInfo);
        LambdaQueryWrapper<CourseItem> tWrapper = new LambdaQueryWrapper<>();
        tWrapper.eq(CourseItem::getCourseNo,resources.getCourseNo());
        courseItemExpMapper.delete(tWrapper);
        if (CollectionUtils.isNotEmpty(resources.getItems())){
            resources.getItems().forEach(s -> {
                CourseItem item = new CourseItem();
                item.setCreateby(SecurityUtils.getCurrentUsername());
                item.setCreateTime(new Timestamp(System.currentTimeMillis()));
                item.setCourseId(courseInfo.getCourseId());
                item.setCourseNo(courseInfo.getCourseNo());
                item.setItemKey(ConstantUtils.COURSE_CATEGORY_KEY);
                item.setItemValue(s.getItemValue());
                item.setItemTitle(s.getItemTitle());
                item.setItemStatus(ElAdminConstant.Valid);
                item.setTrysee(s.getTrysee());
                item.setDuration(s.getDuration());
                courseItemExpMapper.insert(item);
            });
        }
        LambdaQueryWrapper<CourseInfoClockSource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CourseInfoClockSource::getCourseNo,resources.getCourseNo());
        courseInfoClockSourcePlusMapper.delete(wrapper);
        if (CollectionUtils.isNotEmpty(resources.getClassNoList())){
            resources.getClassNoList().forEach(s -> {
                CourseInfoClockSource courseInfoClockSource = new CourseInfoClockSource();
                courseInfoClockSource.setCourseNo(resources.getCourseNo());
                courseInfoClockSource.setClassNo(s);
                courseInfoClockSource.setCreateby(SecurityUtils.getCurrentUsername());
                courseInfoClockSource.setCreateTime(DateUtil.TimestampNow());
                CourseClass courseClass = courseClassService.getClassByClassNo(s);
                if (Objects.nonNull(courseClass)){
                    courseInfoClockSource.setClassName(courseClass.getName());
                    courseInfoClockSource.setClassId(courseClass.getClassId());
                }
                courseInfoClockSourceService.create(courseInfoClockSource);
            });
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CourseInfo resources) {
        CourseInfo courseInfo = courseInfoRepository.findById(resources.getCourseId()).orElseGet(CourseInfo::new);
        ValidationUtil.isNull( courseInfo.getCourseId(),"CourseInfo","id",resources.getCourseId());
        CourseInfo courseInfo1 = null;
        courseInfo1 = courseInfoRepository.findByCourseNo(resources.getCourseNo());
        if(courseInfo1 != null && !courseInfo1.getCourseId().equals(courseInfo.getCourseId())){
            throw new EntityExistException(CourseInfo.class,"course_no",resources.getCourseNo());
        }
        courseInfo.copy(resources);
        courseInfo.setApplicants(ConstantUtils.Applicants);
        courseInfoRepository.save(courseInfo);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long courseId : ids) {
            courseInfoRepository.deleteById(courseId);
        }
    }

    @Override
    public void download(List<CourseInfoDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (CourseInfoDto courseInfo : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("课程编码", courseInfo.getCourseNo());
            map.put("名称", courseInfo.getCourseName());
            map.put("价格", courseInfo.getSellPrice());
            map.put("优惠价", courseInfo.getDiscountPrice());
            map.put("图标", courseInfo.getCourseLogo());
            map.put("横幅图", courseInfo.getCourseBanner());
            map.put("分类ID", courseInfo.getTypeId());
            map.put("创建时间", courseInfo.getCreateTime());
            map.put("创建人", courseInfo.getCreateby());
            map.put("更新时间", courseInfo.getUpdateTime());
            map.put("更新人", courseInfo.getUpdateby());
            map.put("课程类别；视频/音频/文字", courseInfo.getCategory());
            map.put("详细介绍", courseInfo.getCourseInfo());
            map.put("是否展示在首页0：不展示，1：展示", courseInfo.getShowIndex());
            map.put("开班时间", courseInfo.getOpenTime());
            map.put("类型，0：线上，1：线下", courseInfo.getPlatform());
            map.put("排序索引", courseInfo.getSortIndex());
            map.put("优惠价启停，0：停止，1：开启", courseInfo.getShowDiscount());
            map.put("状态，0下架，1：上架", courseInfo.getStatus());
            map.put("显示优秀，0：不展示，1：展示", courseInfo.getShowExcellent());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public CourseInfo getInfoByNo(String courseNo) {

        return courseInfoRepository.findByCourseNo(courseNo);
    }
}